package com.xiaobai.units;

import com.alibaba.fastjson.JSONObject;
import com.arronlong.httpclientutil.HttpClientUtil;
import com.arronlong.httpclientutil.builder.HCB;
import com.arronlong.httpclientutil.common.HttpConfig;
import com.arronlong.httpclientutil.common.HttpHeader;
import com.arronlong.httpclientutil.exception.HttpProcessException;
import com.xiaobai.common.ServerItemResult;
import com.xiaobai.exception.LoginException;
import com.xiaobai.exception.UpdatePasswordException;
import com.xiaobai.service.achievement.AchievementServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.util.Base64Util;

import java.io.UnsupportedEncodingException;
import java.util.*;

@Slf4j
public class HttpUnits {

    /**
     * 仅登录的时候才是要尝试两次!
     */

    public static String loginPost(String username,String password){

        String url = "https://jwxt.gdupt.edu.cn/login!doLogin.action";

        Header[] headers = HttpHeader.custom()
                .build();

        HCB hcb=HttpPool.getHcb();//从池子中获取

        CookieStore httpCookieStore = new BasicCookieStore();

        HttpClient client = hcb.setDefaultCookieStore(httpCookieStore).build();

        Map<String,Object> map=new HashMap<>();
        map.put("account",username);
        map.put("pwd",password);

        //插件式配置请求参数（网址、请求参数、编码、client）
        HttpConfig config = HttpConfig.custom()
                .headers(headers)    //设置headers，不需要时则无需设置
                .url(url)              //设置请求的url
                .map(map)
                .encoding("utf-8") //设置请求和返回编码，默认就是Charset.defaultCharset()
                .client(client)    //如果只是简单使用，无需设置，会自动获取默认的一个client对象
                .timeout(8000)
                ;
        String responseResult=null;
        try {
            HttpClientUtil.post(config);
            responseResult=HttpClientUtil.post(config);//登录需 请求两次
        } catch (HttpProcessException e) {
            Calendar calendar = Calendar.getInstance();
            int hour = calendar.get(Calendar.HOUR_OF_DAY);
            if (hour >= 23 || hour <= 6) {
                // 凌晨就提示教务关网了
                log.error(e.getMessage());
                throw new LoginException("教务网休息了");
            } else{
                log.error("教务网已暂时关闭外网访问");
                e.printStackTrace();
                throw new LoginException("教务网已暂时关闭外网访问");
            }
        }

        if (responseResult == null) {
            throw new LoginException("教务返回数据异常,请稍后再试");
        }

        JSONObject jsonObject = JSONObject.parseObject(responseResult);
        if (responseResult.contains("不正确")) {
            // 返回错误次数
            throw new UpdatePasswordException(jsonObject.getString("msg"));
        }
        if (responseResult.contains("解锁")) {
            throw new UpdatePasswordException("密码错误过多,请稍后再试");
        }
        if (jsonObject.getString("status").equals("n")) {
            log.error("登录时发生未知错误"+responseResult);
            throw new LoginException("登陆时发生未知错误");
        }

        String result=null;

        for(Cookie cookie:httpCookieStore.getCookies()) {
            if(StringUtils.equals(cookie.getName(),"JSESSIONID")){
                result=cookie.getValue();
                break;
            }
        }

        return result;
    }

    private static CloseableHttpClient httpclient = HttpClients.custom().addInterceptorLast(new HttpRequestInterceptor() {
        @Override
        public void process(HttpRequest request, HttpContext context) {
            Header[] cookies = request.getHeaders("Cookie");
            request.removeHeaders("Cookie");
            for (Header cookie : cookies) {
                /**
                 * httpclient会记录上次的cookie(以BufferedHeader存储),所以这里删除上次的cookie。
                 */
                if (cookie instanceof BufferedHeader) {
                    continue;
                }
                request.setHeader(cookie.getName(), cookie.getValue());
            }
        }
    }).build();

    public static ServerItemResult gyLogin(String username,String password) {

        String jsessionId;

        HttpPost httpPost = new HttpPost("https://jwxt.gdupt.edu.cn/login!doLogin.action");
        // 第一次空白登录
        String responseResult = null;
        try(CloseableHttpResponse response = httpclient.execute(httpPost)) {
            responseResult = EntityUtils.toString(response.getEntity());
            jsessionId = response.getLastHeader("Set-Cookie").getElements()[0].getValue();
        } catch (Exception e) {
            Calendar calendar = Calendar.getInstance();
            int hour = calendar.get(Calendar.HOUR_OF_DAY);
            if (hour >= 23 || hour <= 6) {
                // 凌晨就提示教务关网了
                log.error(e.getMessage());
                log.error(responseResult);
                return ServerItemResult.error("教务网休息了");
            } else{
                log.error("教务网已暂时关闭外网访问");
                log.error(responseResult);
                e.printStackTrace();
                return ServerItemResult.error("教务网已暂时关闭外网访问");
            }
        }

        List<NameValuePair> list = new ArrayList<>();
        list.add(new BasicNameValuePair("account", username));
        list.add(new BasicNameValuePair("pwd", Base64Util.encode(password)));
        UrlEncodedFormEntity urlEncodedFormEntity = null;
        try {
            urlEncodedFormEntity = new UrlEncodedFormEntity(list, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 第二次正式登录
        httpPost.setEntity(urlEncodedFormEntity);
        httpPost.setHeader("Cookie", "JSESSIONID=" + jsessionId);
        try(CloseableHttpResponse response = httpclient.execute(httpPost)) {
            responseResult = EntityUtils.toString(response.getEntity());
            log.error(responseResult);
        } catch (Exception e) {
            Calendar calendar = Calendar.getInstance();
            int hour = calendar.get(Calendar.HOUR_OF_DAY);
            if (hour >= 23 || hour <= 6) {
                // 凌晨就提示教务关网了
                log.error(e.getMessage());
                return ServerItemResult.error("教务网休息了");
            } else{
                log.error("教务网已暂时关闭外网访问");
                e.printStackTrace();
                return ServerItemResult.error("教务网已暂时关闭外网访问");
            }
        }

        if (responseResult == null) {
            return ServerItemResult.error("教务返回数据异常,请稍后再试");
        }
        JSONObject jsonObject;
        try {
            jsonObject = JSONObject.parseObject(responseResult);
        }catch (Exception e) {
            log.info("JSON解析错误,请求返回信息:" + responseResult);
            return ServerItemResult.error("教务返回数据异常,请稍后再试");
        }
        if (responseResult.contains("不正确")) {
            // 返回错误次数
            return ServerItemResult.error("密码错误");
        }
        if (responseResult.contains("解锁")) {
            return ServerItemResult.error("密码错误");
        }
        if (jsonObject.getString("status").equals("n")) {
            log.error("登录时发生未知错误"+responseResult);
            return ServerItemResult.error("教务返回数据异常,请稍后再试");
        }

        return ServerItemResult.ok(jsessionId);
    }

    // 供热更新用
    public static ServerItemResult loginPost_V2(String username, String password){

        String url = "https://jwxt.gdupt.edu.cn/login!doLogin.action";

        Header[] headers = HttpHeader.custom()
                .build();

        HCB hcb=HttpPool.getHcb();//从池子中获取

        CookieStore httpCookieStore = new BasicCookieStore();

        HttpClient client = hcb.setDefaultCookieStore(httpCookieStore).build();

        Map<String,Object> map=new HashMap<>();
        map.put("account",username);
        map.put("pwd",Base64Util.encode(password));

        //插件式配置请求参数（网址、请求参数、编码、client）
        HttpConfig config = HttpConfig.custom()
                .headers(headers)    //设置headers，不需要时则无需设置
                .url(url)              //设置请求的url
                .map(map)
                .encoding("utf-8") //设置请求和返回编码，默认就是Charset.defaultCharset()
                .client(client)    //如果只是简单使用，无需设置，会自动获取默认的一个client对象
                .timeout(8000)
                ;
        String responseResult=null;
        try {
            HttpClientUtil.post(config);
            responseResult=HttpClientUtil.post(config);//登录需 请求两次
        } catch (HttpProcessException e) {
            log.info("响应失败:{}", responseResult);
            Calendar calendar = Calendar.getInstance();
            int hour = calendar.get(Calendar.HOUR_OF_DAY);
            if (hour >= 23 || hour <= 6) {
                // 凌晨就提示教务关网了
                log.error(e.getMessage());
                return ServerItemResult.error("教务网休息了");
            } else{
                log.error("教务网已暂时关闭外网访问");
                e.printStackTrace();
                return ServerItemResult.error("教务网已暂时关闭外网访问");
            }
        }

        if (responseResult == null) {
            return ServerItemResult.error("教务返回数据异常,请稍后再试");
        }
        JSONObject jsonObject = null;
        try {
            jsonObject = JSONObject.parseObject(responseResult);
        }catch (Exception e) {
            log.info("JSON解析错误,请求返回信息:" + responseResult);
            return ServerItemResult.error("教务返回数据异常,请稍后再试");
        }
        if (responseResult.contains("不正确")) {
            // 返回错误次数
            return ServerItemResult.error("密码错误");
        }
        if (responseResult.contains("解锁")) {
            return ServerItemResult.error("密码错误");
        }
        if (jsonObject.getString("status").equals("n")) {
            log.error("登录时发生未知错误"+responseResult);
            return ServerItemResult.error("教务返回数据异常,请稍后再试");
        }

        String result=null;

        for(Cookie cookie:httpCookieStore.getCookies()) {
            if(StringUtils.equals(cookie.getName(),"JSESSIONID")){
                result=cookie.getValue();
                break;
            }
        }

        return ServerItemResult.ok(result);
    }

    public static String loginGet(String url){


        HCB hcb=HttpPool.getHcb();//从池子中获取

        HttpClient client = hcb.build();

        //插件式配置请求参数（网址、请求参数、编码、client）
        HttpConfig config = HttpConfig.custom()
                .url(url)              //设置请求的url
                .encoding("utf-8") //设置请求和返回编码，默认就是Charset.defaultCharset()
                .client(client)    //如果只是简单使用，无需设置，会自动获取默认的一个client对象
                .timeout(8000)
                ;

        String result=null;
        try {
            result = HttpClientUtil.get(config);     //get请求
        } catch (HttpProcessException e) {
            log.info("get请求出错!");
            e.printStackTrace();
        }

        return result;
    }

    @SuppressWarnings("all")
    public static String gyGet(String url,String jsessionid,Map paramMap){

        //插件式配置Header（各种header信息、自定义header）
        Header[] headers = HttpHeader.custom()
                .other("Cookie", "JSESSIONID="+jsessionid)
                .build();

        HCB hcb=HttpPool.getHcb();//从池子中获取

        HttpClient client = hcb.build();

        //插件式配置请求参数（网址、请求参数、编码、client）
        HttpConfig config = HttpConfig.custom()
                .headers(headers)    //设置headers，不需要时则无需设置
                .url(url)              //设置请求的url
                .map(paramMap)              //设置请求参数，没有则无需设置
                .encoding("utf-8") //设置请求和返回编码，默认就是Charset.defaultCharset()
                .client(client)    //如果只是简单使用，无需设置，会自动获取默认的一个client对象
                .timeout(8000)
                ;

        String result=null;
        try {
            result = HttpClientUtil.get(config);     //get请求
        } catch (HttpProcessException e) {
            log.info("get请求出错!");
            e.printStackTrace();
        }

        return result;
    }

    @SuppressWarnings("all")
    public static String gyPost(String url,String jsessionid,Map paramMap){

        //插件式配置Header（各种header信息、自定义header）
        Header[] headers = HttpHeader.custom()
                .other("Cookie", "JSESSIONID="+jsessionid)
                .build();

        /**
         * 才不是从池子中获取
         * HCB只是一个配置类,其就是配置新创建的HttpClient。
         */
        HCB hcb=HttpPool.getHcb();// error 从池子中获取

        /**
         * 新创建HttpClient
         */
        HttpClient client = hcb.build();

        /**
         * 每个HttpConfig里面都有一个HttpClient所以才不会发生存储并复用jsessionId的问题,
         */
        //插件式配置请求参数（网址、请求参数、编码、client）
        HttpConfig config = HttpConfig.custom()
                .headers(headers)    //设置headers，不需要时则无需设置
                .url(url)              //设置请求的url
                .map(paramMap)              //设置请求参数，没有则无需设置
                .encoding("utf-8") //设置请求和返回编码，默认就是Charset.defaultCharset()
                .client(client)    //如果只是简单使用，无需设置，会自动获取默认的一个client对象
                .timeout(8000)
                ;

        String result=null;
        try {
            result = HttpClientUtil.post(config);     //get请求
        } catch (HttpProcessException e) {
            log.info("get请求出错!");
            e.printStackTrace();
        }


        return result;
    }

    public static String articleGet(String url){


        HCB hcb=HttpPool.getHcb();//从池子中获取

        HttpClient client = hcb.build();

        //插件式配置请求参数（网址、请求参数、编码、client）
        HttpConfig config = HttpConfig.custom()
                .url(url)              //设置请求的url
                .encoding("utf-8") //设置请求和返回编码，默认就是Charset.defaultCharset()
                .client(client)    //如果只是简单使用，无需设置，会自动获取默认的一个client对象
                .timeout(8000)
                ;

        String result=null;
        try {
            result = HttpClientUtil.get(config);     //get请求
        } catch (HttpProcessException e) {
            log.info("更新每日一文请求出错!");
            e.printStackTrace();
        }


        return result;
    }

    public static UrlEncodedFormEntity generateEntity(Map<String,String> paramsMap) {
        List<NameValuePair> list = new ArrayList<>();
        if (paramsMap != null) {
            for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
                list.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
            }
        }
        UrlEncodedFormEntity urlEncodedFormEntity = null;
        try {
            urlEncodedFormEntity = new UrlEncodedFormEntity(list, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return urlEncodedFormEntity;
    }

    public static void main(String[] args) throws InterruptedException {
        // TCP连接数只与系统底层有关,都会复用
        ServerItemResult serverItemResult = gyLogin("18034520213", "*");
        AchievementServiceImpl achievementService = new AchievementServiceImpl();
        achievementService.selectAllAchievement(serverItemResult.getMsg(), "01");
        achievementService.selectAllAchievement(serverItemResult.getMsg(), "01");
        achievementService.selectAllAchievement(serverItemResult.getMsg(), "01");
        achievementService.selectAllAchievement(serverItemResult.getMsg(), "01");
        achievementService.selectAllAchievement(serverItemResult.getMsg(), "01");
        achievementService.selectAllAchievement(serverItemResult.getMsg(), "01");
        String content = achievementService.selectAllAchievement(serverItemResult.getMsg(), "01");
        System.out.println(content);
    }

}
